home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2000 #5 / Amiga Plus CD - 2000 - No. 5.iso / Tools / Musik / Misc / Amster / Source / upload.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-01-01  |  11.4 KB  |  480 lines

  1. /*
  2. ** Amster - Upload
  3. ** by Jacob Laursen <laursen@myself.com>
  4. */
  5.  
  6. #include "include/config.h"
  7.  
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10.  
  11. #include <proto/dos.h>
  12. #include <proto/exec.h>
  13. #include <proto/socket.h>
  14.  
  15. #include <netdb.h>
  16. #include <sys/time.h>
  17. #include <sys/socket.h>
  18. #include <sys/ioctl.h>
  19. #include <netinet/tcp.h>
  20. #include <bsdsocket/socketbasetags.h>
  21. #include <error.h>
  22. #include <time.h>
  23.  
  24. #include "include/mui.h"
  25. #include <MUI/NListview_mcc.h>
  26. #include "include/gui.h"
  27. #include "include/panel.h"
  28. #include "include/prefs.h"
  29. #include "include/share.h"
  30. #include "include/transfer.h"
  31. #include "include/upload.h"
  32. #include "amster_Cat.h"
  33. #include "include/protos.h"
  34.  
  35.  
  36. #define ULC_STATE 0
  37. #define ULC_SIZE 1
  38.  
  39. int ul_count = 0;
  40.  
  41. ULONG ul_new(struct IClass *cl, Object *obj, struct opSet *msg);
  42. void ul_cps(struct TransferData *data);
  43.  
  44.  
  45. MUIF ul_dispatch(REG(a0) struct IClass *cl,REG(a2) Object *obj,REG(a1) Msg msg)
  46. {
  47.     struct TransferData *data;
  48.  
  49.     switch(msg->MethodID) {
  50.         case OM_NEW:
  51.             return(ul_new(cl, obj, (APTR)msg));
  52.         case MUIM_Window_Setup:
  53.             return(dl_setup(cl, obj, (APTR)msg));
  54.         case MUIM_Window_Cleanup:
  55.             return(dl_muicleanup(cl, obj, (APTR)msg));
  56.         case UPLOAD_OPEN:
  57.             set(obj, MUIA_Window_Open, TRUE);
  58.             return NULL;
  59.         case UPLOAD_CLOSE:
  60.             set(obj, MUIA_Window_Open, FALSE);
  61.             return NULL;
  62.         case UPLOAD_UPDATE:
  63.             {
  64.             long pos = MUIV_NList_GetPos_Start;
  65.             data = INST_DATA(cl, obj);
  66.             DoMethod(data->list, MUIM_NList_GetPos, (((muimsg)msg)->arg1), &pos);
  67.             DoMethod(data->list, MUIM_NList_Redraw, pos);
  68.             return NULL;
  69.             }
  70.         case UPLOAD_CPS:
  71.             data = INST_DATA(cl, obj);
  72.             ul_cps(data);
  73.             return NULL;
  74.         case UPLOAD_ADD:
  75.             data = INST_DATA(cl, obj);
  76.             DoMethod(data->list, MUIM_NList_InsertSingle, (songtrans)(((muimsg)msg)->arg1), MUIV_NList_Insert_Bottom);
  77.             return NULL;
  78.         case UPLOAD_START:
  79.             data = INST_DATA(cl, obj);
  80.             ul_startq2(data, (char *)(((muimsg)msg)->arg1), (char *)(((muimsg)msg)->arg2), (u_long)(((muimsg)msg)->arg3), (int)(((muimsg)msg)->arg4));
  81.             return NULL;
  82.         case UPLOAD_INFO:
  83.             data = INST_DATA(cl, obj);
  84.             TransferInfo(data);
  85.             return NULL;
  86.         case UPLOAD_ABORT:
  87.             data = INST_DATA(cl, obj);
  88.             TransferAbort(data);
  89.             return NULL;
  90.         case UPLOAD_CLEANUP:
  91.             data = INST_DATA(cl, obj);
  92.             TransferCleanup(data);
  93.             return NULL;
  94.         case UPLOAD_CLEANUP_SINGLE:
  95.             {
  96.             long pos;
  97.             songtrans sd = (songtrans)(((muimsg)msg)->arg1);
  98.             data = INST_DATA(cl, obj);
  99.  
  100.             pos = MUIV_NList_GetPos_Start;
  101.             DoMethod(data->list, MUIM_NList_GetPos, sd, &pos);
  102.             DoMethod(data->list, MUIM_NList_Remove, pos);
  103.  
  104.             return NULL;
  105.             }
  106.         case UPLOAD_WATCHER:
  107.             data = INST_DATA(cl, obj);
  108.             TransferWatcher(data);
  109.             return NULL;
  110.         case UPLOAD_COUNTDECREMENT:
  111.             data = INST_DATA(cl, obj);
  112.             if (--ul_count == 0) DoMethod(_app(obj), MUIM_Application_RemInputHandler, &data->watchnode);
  113.             return NULL;
  114.         case UPLOAD_COUNTINCREMENT:
  115.             data = INST_DATA(cl, obj);
  116.             if (ul_count++ == 0) DoMethod(_app(obj), MUIM_Application_AddInputHandler, &data->watchnode);
  117.             return NULL;
  118.     }
  119.     return DoSuperMethodA(cl, obj, msg);
  120. }
  121.  
  122.  
  123. ULONG ul_new(struct IClass *cl, Object *obj, struct opSet *msg)
  124. {
  125.     static struct Hook uplistdispHook = { {0,0}, &translistdisp, NULL, NULL };
  126.     static struct Hook uplistdestHook = { {0,0}, &translistdest, NULL, NULL };
  127.     struct TransferData *data;
  128.     Object *list, *info, *BT_Abort, *BT_Clean;
  129.  
  130.     if (obj = (Object *)DoSuperNew(cl,obj,
  131.         MUIA_Window_Title, MSG_UPLOAD_TITLE,
  132.         MUIA_Window_ID, MAKE_ID('U','P','L','D'),
  133.         WindowContents, VGroup,
  134.             Child, list = NListviewObject,
  135.                 MUIA_NListview_NList, NListObject,
  136.                     InputListFrame,
  137.                     MUIA_Font, MUIV_Font_Tiny,
  138.                     MUIA_NList_Title, TRUE,
  139.                     MUIA_NList_Format, "BAR, BAR, BAR, BAR, BAR",
  140.                     MUIA_NList_DisplayHook, &uplistdispHook,
  141.                     MUIA_NList_DestructHook, &uplistdestHook,
  142.                     MUIA_CycleChain, 1,
  143.                 End,
  144.             End,
  145.             Child, info = TextObject,
  146.                 TextFrame,
  147.                 MUIA_Background, MUII_TextBack,
  148.                 MUIA_Text_PreParse, "\33c",
  149.             End,
  150.             Child, HGroup,
  151.                 Child, BT_Abort = SimpleButton(MSG_UPLOAD_ABORT_GAD),
  152.                 Child, BT_Clean = SimpleButton(MSG_UPLOAD_CLEANUP_GAD),
  153.             End,
  154.         End,
  155.         TAG_MORE, msg->ops_AttrList))
  156.     {
  157.         data = INST_DATA(cl,obj);
  158.         data->list = list;
  159.         data->info = info;
  160.  
  161.         data->ihnode.ihn_Object = obj;
  162.         data->ihnode.ihn_Millis = 1000;
  163.         data->ihnode.ihn_Method = UPLOAD_CPS;
  164.         data->ihnode.ihn_Flags  = MUIIHNF_TIMER;
  165.  
  166.         data->watchnode.ihn_Object = obj;
  167.         data->watchnode.ihn_Millis = 10000;
  168.         data->watchnode.ihn_Method = UPLOAD_WATCHER;
  169.         data->watchnode.ihn_Flags  = MUIIHNF_TIMER;
  170.  
  171.         DoMethod(BT_Abort, MUIM_Notify, MUIA_Pressed, FALSE, obj, 1, UPLOAD_ABORT  );
  172.         DoMethod(BT_Clean, MUIM_Notify, MUIA_Pressed, FALSE, obj, 1, UPLOAD_CLEANUP);
  173.         DoMethod(list, MUIM_Notify, MUIA_NList_EntryClick, MUIV_EveryTime, obj, 1, UPLOAD_INFO);
  174.         DoMethod(obj, MUIM_Notify, MUIA_Window_CloseRequest, TRUE, obj, 1, UPLOAD_CLOSE);
  175.  
  176.         return((ULONG)obj);
  177.     }
  178.     return(0);
  179. }
  180.  
  181.  
  182. void ul_cps(struct TransferData *data)
  183. {
  184.     songtrans sd;
  185.     u_long item;
  186.     int i;
  187.  
  188.     for (i=0; ; i++) {
  189.         DoMethod(data->list, MUIM_NList_GetEntry, i, &item);
  190.         if (!item) return;
  191.         sd = (songtrans)item;
  192.         if (sd->state == DLS_UP) {
  193.             CalculateCps(sd);
  194.             DoMethod(gui->uwin, UPLOAD_UPDATE, sd);
  195.         }
  196.     }
  197. }
  198.  
  199.  
  200. void ul_addq(song s)
  201. /* This is the initial function, called from share.c */
  202. {
  203.     songtrans sd;
  204.     char *path;
  205.  
  206.     path = MakeWinPath(s->title);
  207.     if (ul_count < prf->UploadQueueLimit) {
  208.         sprintf(nap_buf, "%s \"%s\"", s->user, path);
  209.         free(path);
  210.         nap_send(NAPC_UPLOADACCEPT);
  211.     }
  212.     else {
  213.         sprintf(nap_buf, "%s \"%s\" %d", s->user, path, prf->UploadQueueLimit);
  214.         free(path);
  215.         nap_send(NAPC_LOCALQUEUEFULL);
  216.         return;
  217.     }
  218.  
  219.     sd = malloc(sizeof(_songtrans));
  220.     if (!sd) return;
  221.     memset(sd, 0, sizeof(_songtrans));
  222.  
  223.     sd->song = nap_songdup(s);
  224.     if (!sd->song) {
  225.         free(sd);
  226.         return;
  227.     }
  228.  
  229.     sd->size = s->size;
  230.     sd->mynick = prf->user;
  231.     sd->type = TYPE_UPLOAD_OUT;
  232.     sd->reqtime = time(NULL);
  233.  
  234.     DoMethod(gui->uwin, UPLOAD_COUNTINCREMENT);
  235.  
  236.     DoMethod(gui->uwin, UPLOAD_ADD, sd);
  237. }
  238.  
  239.  
  240. void ul_startq(char *title, char *user, u_long ip, int port, int link)
  241. /* This is the initial function, when the actual upload is about to
  242.    take place (acknowledged by server) - called from napster.c */
  243. {
  244.     DoMethod(gui->uwin, UPLOAD_START, title, user, ip, port);
  245. }
  246.  
  247.  
  248. void ul_startq2(struct TransferData *data, char *title, char *user, u_long ip, int port)
  249. /* ul_startq() continued (to get TransferData struct) */
  250. {
  251.     u_long tmp;
  252.     songtrans sd;
  253.     long i;
  254.     char *path;
  255.  
  256.     for (i=0; ; i++) {
  257.         DoMethod(data->list, MUIM_NList_GetEntry, i, &tmp);
  258.         if (!tmp) return;
  259.         sd = (songtrans)tmp;
  260.         path = MakeWinPath(sd->song->title);
  261.         if (sd->state==DLS_PREP && stricmp(user, sd->song->user)==0 && strcmp(title, path)==0) break;
  262.     }
  263.     free(path);
  264.  
  265.     if (sd->t) return;    /* Already in a thread */
  266.  
  267.     /* We haven't filled out sd->song completely yet, since not much
  268.        information was available when the request was made */
  269.     sd->song->ip = ip;
  270.  
  271.     /* Why do we need the IP twice? Check and use only one of them! */
  272.     sd->ip = ip;
  273.     sd->port = port;
  274.  
  275.     sd->t = th_spawn(ul_handlemsg, "Amster uploader", UploadThread, prf->UploadTaskPri, sd);
  276.     if (!sd->t) {
  277.         sd->state = DLS_ERROR;
  278.         DoMethod(gui->uwin, DL_UPDATE, sd);
  279.     }
  280. }
  281.  
  282.  
  283. void ul_handlemsg(thread t, int com, APTR data)
  284. {
  285.     songtrans sd=(songtrans)t->data;
  286.  
  287.     switch(com) {
  288.         case THC_STARTUP:
  289.             sd->ts = 1;
  290.             nap_sendbuf(NAPC_ULINC, "");
  291.             break;
  292.         case THC_EXIT:
  293.             sd->error = (int)data;
  294.             if (sd->error == 0) DoMethod(gui->shwin, SHARE_UPDCOUNT, sd->song->title);
  295.             TransferHandleError(sd);
  296.             sd->ts = 0;
  297.             sd->t = NULL;
  298.             DoMethod(gui->uwin, UPLOAD_COUNTDECREMENT);
  299.             nap_sendbuf(NAPC_ULCOMPLETE, "");
  300.             if (sd->state == DLS_FIN && prf->AutoCleanup) {
  301.                 DoMethod(gui->uwin, UPLOAD_CLEANUP_SINGLE, sd);
  302.                 break;
  303.             }
  304.             break;
  305.         case DLC_STATE:
  306.             sd->state = (int)data;
  307.         case DLC_UPDATE:
  308.             DoMethod(gui->uwin, UPLOAD_UPDATE, sd);
  309.             break;
  310.     }
  311. }
  312.  
  313.  
  314. /* Upload thread */
  315.  
  316. __asm __saveds void UploadThread(void)
  317. {
  318.     thread t;
  319.     songtrans sd;
  320.     struct Library *DosBase;
  321.     struct Library *SocketBase;
  322.     char *buffer, *path;
  323.     long tmp;
  324.     long s;
  325.     thmsg m;
  326.     int len;
  327.  
  328.     t = thr_init();
  329.     if (!t) return;
  330.     sd = t->data;
  331.  
  332.     if (!InitTransferThread(t, sd)) return;
  333.     s = sd->s;
  334.     buffer = sd->buffer;
  335.     DosBase = sd->DosBase;
  336.     SocketBase = sd->SocketBase;
  337.  
  338.     while (1) {
  339.         u_long sigs;
  340.  
  341.         sigs = Wait(sd->nsigm|sd->msigm);
  342.         if (sigs&(sd->msigm)) {
  343.             m = (thmsg)GetMsg(t->port);
  344.             if(m) {
  345.                 if (m->com == THC_EXIT) {
  346.                     thr_message(t, DLC_STATE, (APTR)DLS_ABORT);
  347.                     ExitTransferThread(sd, 0);
  348.                     return;
  349.                 }
  350.                 if (!m->isreply) {
  351.                     m->isreply=1;
  352.                     ReplyMsg((struct Message *)m);
  353.                 }
  354.             }
  355.         }
  356.  
  357.         if (sigs&(sd->nsigm)) {
  358.             FD_ZERO(&sd->fds);
  359.             FD_SET(s,&sd->fds);
  360.             sd->tv.tv_sec = 0;
  361.             sd->tv.tv_usec = 0;
  362.  
  363.             switch(sd->state) {
  364.                 case DLS_CON:
  365.                     if (WaitSelect(s+1,NULL,&sd->fds,NULL,&sd->tv,0) != 1) break;
  366.                     {
  367.                         sd->state = DLS_INIT;
  368.                         tmp = 0;
  369.                         IoctlSocket(s, FIONBIO, (char*)&tmp);
  370.                         /* Disable non-blocking I/O to the socket */
  371.                     }
  372.  
  373.                 case DLS_INIT:
  374.                     if (WaitSelect(s+1,&sd->fds,NULL,NULL,&sd->tv,0) != 1) break;
  375.                     {
  376.                         tmp = recv(s, buffer, 1, 0);
  377.                         if (tmp != 1) {
  378.                             sd->ErrorCode = Errno();
  379.                             ExitTransferThread(sd, ERROR_NET);
  380.                             return;
  381.                         }
  382.                         if (buffer[0] != '1') {
  383.                             ExitTransferThread(sd, 30);
  384.                             return;
  385.                         }
  386.                         thr_message(t, DLC_UPDATE, 0);
  387.                         send(s, "SEND", 4, 0);
  388.  
  389.                         path = MakeWinPath(sd->song->title);
  390.                         sprintf(buffer, "%s \"%s\" %ld", sd->mynick, path, sd->song->size);
  391.                         free(path);
  392.                         send(s, buffer, strlen(buffer),0);
  393.  
  394.                         tmp = recv(s, buffer, 32, 0);
  395.                         if (tmp < 1) {
  396.                             sd->ErrorCode = Errno();
  397.                             ExitTransferThread(sd, ERROR_NET);
  398.                             return;
  399.                         }
  400.                         buffer[tmp] = '\0';
  401.  
  402.                         sd->cur = atoi(buffer);
  403.                         if (sd->cur == 0 && buffer[0] != '0') {
  404.                             if (strcmp(buffer, "FILE NOT REQUESTED") == 0) {
  405.                                 ExitTransferThread(sd, ERROR_NOTREQUESTED);
  406.                                 return;
  407.                             }
  408.                             ExitTransferThread(sd, 31);
  409.                             return;
  410.                         }
  411.  
  412.                         sd->f = Open(sd->song->title, MODE_OLDFILE);
  413.                         if (!sd->f) {
  414.                             sd->ErrorCode = IoErr();
  415.                             ExitTransferThread(sd, ERROR_FILEOPEN);
  416.                             return;
  417.                         }
  418.  
  419.                         Seek(sd->f, sd->cur, OFFSET_BEGINNING);
  420.                         sd->state = DLS_UP;
  421.                         sd->starttime = time(NULL);
  422.                         sd->resumestart = sd->cur;
  423.                         thr_message(t, DLC_UPDATE, 0);
  424.                     }
  425.  
  426.                 case DLS_UP:
  427.                     if (WaitSelect(s+1,NULL,&sd->fds,NULL,&sd->tv,0) != 1) break;
  428.                     while (sd->cur < sd->size) {
  429.  
  430.                         len = Read(sd->f, buffer, 4096);
  431.                         if (len == -1) {    /* Error */
  432.                             sd->ErrorCode = IoErr();
  433.                             ExitTransferThread(sd, ERROR_FILEREAD);
  434.                             return;
  435.                         }
  436.                         if (len != 0) {
  437.                             tmp = send(s, buffer, len, 0);
  438.                             if (tmp == -1) {
  439.                                 sd->ErrorCode = Errno();
  440.                                 ExitTransferThread(sd, ERROR_NET);
  441.                                 return;
  442.                             }
  443.                             sd->cur += len;
  444.                         }
  445.  
  446.                         if (len < 4096 && sd->cur < sd->size) {
  447.                             /* Read buffer wasn't filled and file is not finished */
  448.                             thr_message(t, DLC_STATE, (APTR)DLS_ERROR);
  449.                             ExitTransferThread(sd, 33);
  450.                             return;
  451.                         }
  452.  
  453.                         m = (thmsg)GetMsg(t->port);
  454.                         if (m) {
  455.                             if (m->com == THC_EXIT) {
  456.                                 thr_message(t, DLC_STATE, (APTR)DLS_ABORT);
  457.                                 ExitTransferThread(sd, 0);
  458.                                 return;
  459.                             }
  460.                             if (!m->isreply) {
  461.                                 m->isreply=1;
  462.                                 ReplyMsg((struct Message *)m);
  463.                             }
  464.                         }
  465.  
  466.                         FD_ZERO(&sd->fds);
  467.                         FD_SET(s,&sd->fds);
  468.                     }
  469.  
  470.                     thr_message(t, DLC_STATE, (APTR)DLS_FIN);
  471.                     ExitTransferThread(sd, 0);
  472.                     return;
  473.  
  474.             }
  475.         }
  476.     }
  477.  
  478.     ExitTransferThread(sd, 0);
  479. }
  480.